home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / DevTools / ClassEditor.0.4 / Source / RZBrowserCell.subproj / RZBrowserCell.m < prev    next >
Encoding:
Text File  |  1995-05-29  |  10.1 KB  |  449 lines

  1. /*
  2.  * RZBrowserCell
  3.  *
  4.  * A subclass of BrowserCell supporting fixed and variable position tabs,
  5.  * multi-font text and inline graphics.
  6.  *
  7.  * Here is an example of setting up a Browser to use a RZBrowserCell:
  8.  *
  9.  *     // create a prototype cell for the browser
  10.  *     id cellPrototype = [[RZBrowserCell alloc] init];
  11.  *     
  12.  *     // initialize the tab stops 
  13.  *     // fixed tab at 10 pixels 
  14.  *     [cellPrototype addFixedTab:10.0];
  15.  *     
  16.  *     // proportional tab at 20% with min at 30 and max at 600 pixels 
  17.  *     [cellPrototype addProportionalTab:0.2 min:30 max:600];
  18.  *     
  19.  *     // fixed tab 60 pixels from right side 
  20.  *     [cellPrototype addFixedTab:-60.0];
  21.  *     
  22.  *     // make sure to set the prototype before we've loaded any columns
  23.  *     [browser setCellPrototype:cellPrototype];
  24.  *     [browser loadColumnZero];
  25.  *     [[browser window] makeKeyAndOrderFront:self];
  26.  *
  27.  *
  28.  * You may freely copy, distribute and reuse the code in this example.
  29.  * This code is provided AS IS without warranty of any kind, expressed 
  30.  * or implied, as to its fitness for any particular use.
  31.  *
  32.  * Copyright 1995 Ralph Zazula (rzazula@next.com).  All Rights Reserved.
  33.  *
  34.  */
  35.  
  36.  
  37. #import "RZBrowserCell.h"
  38. #import "RZSortedList.h"
  39. #import "RZTextToken.h"
  40. #import "RZTabStop.h"
  41. #import "RZSimpleString.h"
  42. #import "RZRefCountedList.h"
  43. #import <appkit/appkit.h>
  44.  
  45. #define BORDER 1
  46.  
  47. @interface RZBrowserCell(Private)
  48. - _addTab:(RZTabStop *)aTab;
  49. - _addText:(RZTextToken *)aText;
  50. - _drawToken:(RZTextToken *)token inside:(const NXRect *)cellFrame inView:controlView;
  51. @end
  52.  
  53. @implementation RZBrowserCell
  54.  
  55. - copyFromZone:(NXZone *)zone
  56. {
  57.     if(self = [super copyFromZone:zone]) {
  58.         if(tabStops) {
  59.             [tabStops addReference];
  60.         }
  61.         if(textTokens) {
  62.             [textTokens addReference];
  63.         }
  64.     }
  65.     return self;
  66. }
  67.  
  68. - free
  69. {
  70.     if(tabStops) {
  71.         tabStops = [[tabStops freeObjects] free];
  72.     }
  73.     if(textTokens) {
  74.         textTokens = [[textTokens freeObjects] free];
  75.     }
  76.     return [super free];
  77. }
  78.  
  79. - setFont:fontObj
  80. {
  81.   [super setFont:fontObj];
  82.   /*
  83.    * save this info so we don't have to look it up every time we draw
  84.    * Note:  support for a TextCell is a font object
  85.    */
  86.   NXTextFontInfo(support, &ascender, &descender, &lineHeight);
  87.   return self;
  88. }    
  89.  
  90. - calcCellSize:(NXSize *)theSize inRect:(const NXRect *)aRect
  91. {    
  92.     NXRect b;
  93.     
  94.     [super calcCellSize:theSize inRect:aRect];
  95.     [[self controlView] getBounds:&b];
  96.     theSize->width = b.size.width;
  97.     return self;
  98. }
  99.  
  100. - drawInside:(const NXRect *)cellFrame inView:controlView
  101. {
  102.     int i, count;
  103.     
  104.     if([[self font] screenFont]) {
  105.         [[[self font] screenFont] set];
  106.     } else {
  107.         [[self font] set];
  108.     }
  109.  
  110.     /* erase the cell */
  111.     PSsetgray((cFlags1.state || cFlags1.highlighted) ? NX_WHITE : NX_LTGRAY);
  112.     NXRectFill(cellFrame);
  113.  
  114.     /* draw the individual tokens */
  115.     count = [textTokens count];
  116.     for(i=0; i<count; i++) {
  117.         [self _drawToken:(RZTextToken *)[textTokens objectAt:i] 
  118.             inside:cellFrame inView:controlView];
  119.     }
  120.  
  121. #if BORDER
  122.     /* all drawing from now on will be in dark gray */
  123.     PSsetgray(NX_DKGRAY);
  124.     
  125.     /* draw the two dark gray lines above and below the cell */
  126.     if (cFlags1.state || cFlags1.highlighted) {
  127.         NXRect  rectArray[2];
  128.         /*
  129.             * draw 1-pixel tall rectangles instead of lines (this is faster than
  130.             * PSmoveto(); PSlineto()). 
  131.             */
  132.         NXSetRect(&(rectArray[0]), NX_X(cellFrame), NX_Y(cellFrame),
  133.                 NX_WIDTH(cellFrame), 1.0);
  134.         NXSetRect(&(rectArray[1]), NX_X(cellFrame), NX_MAXY(cellFrame) - 1.0,
  135.                 NX_WIDTH(cellFrame), 1.0);
  136.     
  137.         /* using NXRectFillList is faster than separate calls to NXRectFill */
  138.         NXRectFillList(rectArray, 2);
  139.     }
  140. #endif
  141.  
  142.     return self;
  143. }
  144.  
  145. - highlight:(const NXRect *)cellFrame inView:controlView lit:(BOOL)flag
  146. {
  147.     if (cFlags1.highlighted != flag) {
  148.         cFlags1.highlighted = flag;
  149.         [self drawInside:cellFrame inView:controlView];
  150.     }
  151.     return self;
  152. }
  153.  
  154. /*** manipulating tabs ***/
  155.  
  156. - addProportionalTab:(float)position
  157. {
  158.     return [self addProportionalTab:position min:0.0 max:0.0];
  159. }
  160.  
  161. - addProportionalTab:(float)position min:(float)minPos max:(float)maxPos
  162. {
  163.     id aTab = [[RZTabStop alloc] initProportional:position min:minPos max:maxPos];
  164.     [self _addTab:aTab];
  165.     return self;
  166. }
  167.  
  168. - addFixedTab:(float)position
  169. {
  170.     id aTab = [[RZTabStop alloc] initFixed:position];
  171.     [self _addTab:aTab];
  172.     return self;
  173. }
  174.     
  175. - clearTabs
  176. {
  177.     if(tabStops) {
  178.         [tabStops freeObjects];
  179.     }
  180.     return self;
  181. }
  182.  
  183. /*** manipulating text tokens ***/
  184.  
  185. - setText:(const char *)format at:(unsigned)index font:(char)font color:(char)color, ...
  186. {
  187.     va_list args;
  188.     static char buf[1024];
  189.     
  190.     va_start(args, format);
  191.     vsprintf(buf, format, args);
  192.     
  193.     [self _addText:[[RZTextToken alloc] initText:buf at:index font:font color:color]];
  194.     
  195.     return self;
  196. }
  197.  
  198. - setText:(const char *)format at:(unsigned)index, ...
  199. {
  200.     va_list args;
  201.     static char buf[1024];
  202.     
  203.     va_start(args, format);
  204.     vsprintf(buf, format, args);
  205.     
  206.     [self _addText:[[RZTextToken alloc] initText:buf at:index]];
  207.     
  208.     return self;
  209. }
  210.  
  211. - setText:(const char *)format at:(unsigned)index font:(char)font, ...
  212. {
  213.     va_list args;
  214.     static char buf[1024];
  215.     
  216.     va_start(args, format);
  217.     vsprintf(buf, format, args);
  218.     
  219.     [self _addText:[[RZTextToken alloc] initText:buf at:index font:font color:0]];
  220.     
  221.     return self;
  222. }
  223.  
  224. - setText:(const char *)format at:(unsigned)index color:(char)color, ...
  225. {
  226.     va_list args;
  227.     static char buf[1024];
  228.     
  229.     va_start(args, format);
  230.     vsprintf(buf, format, args);
  231.     
  232.     [self _addText:[[RZTextToken alloc] initText:buf at:index font:0 color:color]];
  233.     
  234.     return self;
  235. }
  236.  
  237. - clearText
  238. {
  239.     if(textTokens) {
  240.         [textTokens freeObjects];
  241.     }
  242.     return self;
  243. }
  244.  
  245. /*** manipulating icons ***/
  246.  
  247. - setImageNamed:(const char *)name at:(unsigned)index
  248. {
  249.     [self _addText:[[RZTextToken alloc] initImage:name at:index]];
  250.     return self;
  251. }
  252.         
  253. /*** archiving ***/
  254.  
  255. - write:(NXTypedStream *)ts
  256. {
  257.     [super write:ts];
  258.     NXWriteTypes(ts, "fff@@", &ascender, &descender, &lineHeight, &tabStops, &textTokens);
  259.     return self;
  260. }
  261.  
  262. - read:(NXTypedStream *)ts
  263. {
  264.     [super read:ts];
  265.     NXReadTypes(ts, "fff@@", &ascender, &descender, &lineHeight, &tabStops, &textTokens);
  266.     return self;
  267. }
  268.  
  269. @end
  270.  
  271. @implementation RZBrowserCell(Private)
  272.  
  273. - _addTab:(RZTabStop *)aTab
  274. {
  275.     if(!tabStops) {
  276.         tabStops = [[RZRefCountedList alloc] init];
  277.     }
  278.     [tabStops addObject:aTab];
  279.     return self;
  280. }
  281.  
  282. - _addText:(RZTextToken *)aText
  283. {
  284.     int i;
  285.         
  286.     if(!textTokens) {
  287.         textTokens = [[RZSortedList alloc] init];
  288.     }
  289.     /* remove any tokens at the same index */
  290.     for(i=0; i<[textTokens count]; i++) {
  291.         if([(RZTextToken *)[textTokens objectAt:i] position] == [aText position]) {
  292.             [[textTokens removeObjectAt:i] free];
  293.         }
  294.     }
  295.     [textTokens addObject:aText];
  296.     return self;
  297. }
  298.  
  299. - _drawToken:(RZTextToken *)token inside:(const NXRect *)cellFrame inView:controlView
  300. {
  301.     static id textCell = nil;
  302.  
  303.     switch([token isText]) {
  304.         case YES : {                        // text
  305.             NXRect rect = *cellFrame;
  306.             RZTabStop *thisStop, *nextStop;
  307.             float thisStopPos, nextStopPos;
  308.             
  309.             if(!textCell) {
  310.                 textCell = [[TextFieldCell alloc] init];
  311.                 [textCell setWrap:NO];
  312.             }
  313.             [textCell setFont:[self font]];
  314.             
  315.             thisStop = [tabStops objectAt:[token position]];
  316.             nextStop = [tabStops objectAt:([token position] + 1)];
  317.             
  318.             if([thisStop fixed]) {
  319.                 thisStopPos = [thisStop position];
  320.                 if(thisStopPos < 0.0) {
  321.                     thisStopPos += NX_WIDTH(cellFrame);
  322.                 }
  323.             } else {
  324.                 thisStopPos = [thisStop position] * NX_WIDTH(cellFrame);
  325.                     
  326.                 if(([thisStop max] > 0.0) && (thisStopPos > [thisStop max])) {
  327.                     thisStopPos = [thisStop max];
  328.                 }
  329.                 if(thisStopPos < [thisStop min]) {
  330.                     thisStopPos = [thisStop min];
  331.                 }
  332.             }
  333.             
  334.             if(nextStop) {
  335.                 if([nextStop fixed] ) {
  336.                     nextStopPos = [nextStop position];
  337.                     if(nextStopPos < 0.0) {
  338.                         nextStopPos += NX_WIDTH(cellFrame);
  339.                     }
  340.                 } else {
  341.                     nextStopPos = [nextStop position] * NX_WIDTH(cellFrame);
  342.                         
  343.                     if(([nextStop max] > 0.0) && (nextStopPos > [nextStop max])) {
  344.                         nextStopPos = [nextStop max];
  345.                     }
  346.                     if(nextStopPos < [nextStop min]) {
  347.                         nextStopPos = [nextStop min];
  348.                     }
  349.                 }
  350.             } else {
  351.                 nextStopPos = 0.0;
  352.             }
  353.             
  354.             /* move to the correct tab position */
  355.             if(nextStopPos > 0.0) {
  356.                 NX_WIDTH(&rect) = nextStopPos - thisStopPos;
  357.             } else {
  358.                 NX_WIDTH(&rect) -= thisStopPos;
  359.             }
  360.             
  361.             NX_X(&rect) = thisStopPos;
  362. //            NX_Y(&rect) += descender - 1;
  363.                         
  364.             /* set the gray level */
  365.             switch([token color]) {
  366.                 default :
  367.                 case 0 :
  368.                     [textCell setTextGray:NX_BLACK];
  369.                     break;
  370.                 case 1 :
  371.                     [textCell setTextGray:NX_DKGRAY];
  372.                     break;
  373.                 case 2 :
  374.                 case 3 :
  375.                     if(cFlags1.state || cFlags1.highlighted) {
  376.                         [textCell setTextGray:NX_LTGRAY];
  377.                     } else {
  378.                         [textCell setTextGray:NX_WHITE];
  379.                     }
  380.                     break;
  381.             }
  382.  
  383.             /* set the font */
  384.             {
  385.             id newFont;
  386.             char buf[128];
  387.                 switch([token font]) {    
  388.                     default :
  389.                     case 0 :
  390.                         sprintf(buf, "%s", [[self font] familyName]);
  391.                         newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
  392.                         break;
  393.                     case 1 :
  394.                         sprintf(buf, "%s-Bold", [[self font] familyName]);
  395.                         newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
  396.                         break;
  397.                     case 2 :
  398.                         sprintf(buf, "%s-Oblique", [[self font] familyName]);
  399.                         newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
  400.                         break;
  401.                     case 3 :
  402.                         sprintf(buf, "%s-BoldOblique", [[self font] familyName]);
  403.                         newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
  404.                         break;
  405.                 }
  406.                 [textCell setFont:newFont];
  407.             }
  408.             
  409.             [textCell setStringValue:(char *)[[token data] string]];
  410.             [textCell drawInside:&rect inView:controlView];
  411.             break;
  412.         }
  413.         
  414.         case NO : {                        // icon
  415.             float thisStopPos;
  416.             RZTabStop *thisStop = [tabStops objectAt:[token position]];
  417.             NXPoint p = cellFrame->origin;
  418.             NXSize imageSize;
  419.             
  420.             if([thisStop fixed]) {
  421.                 thisStopPos = [thisStop position];
  422.                 if(thisStopPos < 0.0) {
  423.                     thisStopPos += NX_WIDTH(cellFrame);
  424.                 }
  425.             } else {
  426.                 thisStopPos = [thisStop position] * NX_WIDTH(cellFrame);
  427.                     
  428.                 if(([thisStop max] > 0.0) && (thisStopPos > [thisStop max])) {
  429.                     thisStopPos = [thisStop max];
  430.                 }
  431.                 if(thisStopPos < [thisStop min]) {
  432.                     thisStopPos = [thisStop min];
  433.                 }
  434.             }
  435.  
  436.             [[token data] getSize:&imageSize];
  437.             p.x += thisStopPos;
  438.             p.y += NX_HEIGHT(cellFrame) - (NX_HEIGHT(cellFrame) - imageSize.height) / 2.0;
  439.             [[token data] composite:NX_SOVER toPoint:&p];
  440.  
  441.             break;
  442.         }
  443.         
  444.     }
  445.     return self;
  446. }
  447.  
  448. @end
  449.